use std::fmt;
use std::ops::{Deref, DerefMut, Drop};
use std::io::{Result,Error,ErrorKind};

use super::gp::GTP;
use super::raw::Raw;

pub struct UBox<T> {
    gp: GTP<T>,
    data: std::ptr::NonNull<T>,
}

impl<T> UBox<T> {
    pub fn from_gpr(gp:GTP<T>,raw:Raw) -> Result<UBox<T>> {
        match raw.h {
            Some(p) => {
                let ptr = std::ptr::NonNull::<T>::new(p as *mut T).ok_or(Error::new(ErrorKind::Other, "null point"))?;
                Ok(UBox::<T>{gp:gp,data:ptr})
            },
            None => Err(Error::new(ErrorKind::Other, "invalid raw")),
        }
    }
    pub fn offset(&self) -> usize { self.gp.gp.offset as usize }
}
impl<T> fmt::Display for UBox<T>
where
    T: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "gp:{} {:?}", self.gp, self.data)
    }
}
impl<T> Drop for UBox<T> {
    fn drop(&mut self) {}
}
impl<T> Deref for UBox<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { self.data.as_ref() }
    }
}
impl<T> DerefMut for UBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.data.as_mut() }
    }
}
